package com.gitee.mp.core.mapper;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ClassUtil;
import com.gitee.mp.annotation.Mapper;
import com.gitee.mp.core.connector.MilvusConnector;
import com.gitee.mp.core.connector.MilvusConnectorFactory;
import com.gitee.mp.core.exception.NoneMatchException;
import com.gitee.mp.extend.MapperInterceptor;
import com.gitee.mp.extend.DefinitionParser;
import lombok.Getter;

import java.lang.reflect.Proxy;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author hongda.li
 */
@Getter
public class MilvusMapperFactory {

    private final ClassLoader classLoader;

    private final DefinitionParser definitionParser;

    private final MilvusConnectorFactory connectorFactory;

    private final List<MapperInterceptor> interceptorList;

    private final Map<Class<?>, Object> proxyCacheMap = new ConcurrentHashMap<>();

    public MilvusMapperFactory(DefinitionParser definitionParser,
                               MilvusConnectorFactory connectorFactory,
                               List<MapperInterceptor> interceptorList) {
        this.interceptorList = interceptorList;
        this.connectorFactory = connectorFactory;
        this.definitionParser = definitionParser;
        this.classLoader = ClassUtil.getClassLoader();
    }

    public <T> T getMapper(Class<T> clazz) {
        return clazz.cast(this.proxyCacheMap.computeIfAbsent(clazz, key -> this.createMapperProxy(clazz)));
    }

    public <T> T createMapperProxy(Class<T> clazz) {
        if (!clazz.isInterface()) {
            throw new NoneMatchException("None match for the interface of mapper : {}", clazz.getName());
        }

        Mapper annotation = AnnotationUtil.getAnnotation(clazz, Mapper.class);
        if (annotation == null) {
            throw new NoneMatchException("None match for the annotation of mapper : {}", clazz.getName());
        }

        MilvusConnector connector = this.connectorFactory.getConnector(annotation.value());
        if (connector == null) {
            throw new NoneMatchException("None match for the connector of mapper : {}", clazz.getName());
        }

        // 获取适用于当前Mapper的拦截器
        List<MapperInterceptor> interceptors = this.interceptorList.stream()
                .filter(item -> item.supported(clazz))
                .sorted(Comparator.comparingInt(MapperInterceptor::order))
                .toList();

        // 创建代理逻辑处理器
        MilvusMapperHandler handler = new MilvusMapperHandler(clazz,
                connector,
                this.definitionParser,
                interceptors);

        // 创建代理对象
        return clazz.cast(Proxy.newProxyInstance(this.classLoader, new Class[]{clazz}, handler));
    }
}
